import React, { PureComponent } from 'react';

class Input extends PureComponent<any, any> {
  el = React.createRef<any>();
  inputing = false;
  inputSelection: {
    start: number;
    end: number;
  } | null = null;

  handleChange = (e: any) => {
    this.restoreCursorLocation();
    if (this.props.onChange) {
      this.props.onChange(e);
    }
  };

  componentDidUpdate() {
    this.forceSetValue();
    this.restoreCursorLocation();
  }

  /**
   * 根据情况恢复光标的位置
   * 如果光标的位置小于值的长度，那么可以判定属于中间编辑的情况
   * 此时恢复光标的位置
   */
  restoreCursorLocation = () => {
    let ele = this.el.current;
    if (!ele) return;
    const { value } = ele;
    let newVal = value.replace(/\s/g, '');
    if (this.inputSelection) {
      const { start, end } = this.inputSelection;
      if (start < newVal.length) {
        new Promise<void>(resolve => resolve()).then(() => {
          ele.selectionStart = start;
          ele.selectionEnd = end;
          this.inputSelection = null;
        });
      }
    }
  };

  forceSetValue = () => {
    const { value } = this.props;
    if ('value' in this.props && this.el.current) {
      const input: any = this.el.current;
      input.value = value;
      input.setAttribute('value', value);
    }
  };

  componentWillUnmount() {
    this.inputSelection = null;
  }

  render() {
    const {
      onChange,
      onFocus,
      onBlur,
      value,
      defaultValue,
      ...attrs
    } = this.props;
    const _value =
      'value' in this.props
        ? value
        : 'defaultValue' in this.props
        ? defaultValue
        : null;
    return (
      <input
        {...attrs}
        defaultValue={_value}
        ref={input => {
          if (!input) {
            return;
          }
          // @ts-ignore
          this.el.current = input;
          // this.forceSetValue();
        }}
        // react 在focus/blur时会重新设值，如果没有下面的操作，会导致focus/blur之后，变空
        onFocus={e => {
          setTimeout(this.forceSetValue, 10);
          onFocus && onFocus(e);
        }}
        onBlur={e => {
          setTimeout(this.forceSetValue, 150);
          onBlur && onBlur(e);
        }}
        onCompositionStart={() => {
          this.inputing = true;
        }}
        onCompositionEnd={e => {
          this.inputing = false;
          this.handleChange(e);
        }}
        onChange={e => {
          if (!this.inputing) {
            this.handleChange(e);
          }
        }}
      />
    );
  }
}

export default Input;
